package com.chen.blue.security.service.login;

import cn.hutool.core.util.StrUtil;
import com.chen.blue.domain.model.system.LoginUser;

import com.chen.blue.domain.model.system.UsersModel;
import com.chen.blue.exception.e.AccountOffException;
import com.chen.blue.exception.e.DtoNullException;
import com.chen.blue.exception.e.PasswordErrorException;
import com.chen.blue.exception.e.UserNameNullException;
import com.chen.blue.redis.service.RedisService;
import com.chen.blue.result.DataResult;
import com.chen.blue.service.redis.RedisKeysManager;
import com.chen.blue.service.system.IUserRoleService;
import com.chen.blue.service.system.IUsersService;
import com.chen.blue.sysconfig.SystemConfig;
import com.chen.blue.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created By CLT On 2023/10/30.
 */
@SuppressWarnings("all")
@Slf4j
@Component("loginService")
public class LoginService {

    /**
     * Object principal 上下文数据
     * Object credentials 相当于密码
     * Collection<? extends GrantedAuthority> authorities 相当于用户角色
     */

    @Resource
    private SystemConfig systemConfig;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Resource
    private RedisService iRedisService;

    @Resource
    private IUserRoleService iUserRoleService;

    @Resource
    private IUsersService userService;


    /**
     * 调用security认证方法
     *
     * @param loginUser
     */
    public String loginHandler(LoginUser loginUser) throws DtoNullException, AccountOffException {

        accountIsOff(loginUser.getUsername());

        /**
         * 认证
         */
        Authentication authentication = null;
        try {
            if (Objects.nonNull(loginUser)) {
                /**
                 * 调用userDetilService获取数据库用户UserDetils和loginUser进行对比认证
                 */
                authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword()));
            }
        } catch (Exception e) {
            log.error("{}", e.getMessage());
            if (e instanceof BadCredentialsException) {
                throw new PasswordErrorException("密码错误");
            } else {
                throw new UserNameNullException("用户不存在");
            }
        }

        setPermission(loginUser.getUsername());

        /**
         * 认证通过生成令牌
         */
        String token = TokenUtil.getToken(loginUser.getUsername(), systemConfig.getTokenSign());
        setToken(token, loginUser.getUsername());

        return token;

    }


    protected void setToken(String token, String username) {

        String key = systemConfig.getTokenSave() + username;

        RedisKeysManager.addRedisKey(key);

        boolean isExist = iRedisService.isExist(key);
        if (isExist) {
            iRedisService.remove(key);
        }

        iRedisService.set(key, token);
        iRedisService.expire(key, Long.parseLong(systemConfig.getExpireTime() + ""));

    }


    /**
     * 将用户的权限存入redis
     *
     * @param username
     * @throws DtoNullException
     */
    protected void setPermission(String username) throws DtoNullException {

        UsersModel currentUser = userService.getUserByUsername(username);

        DataResult<List<String>> dataResult = iUserRoleService.queryRoleCodeById(currentUser.getId());
        List<String> dataList = dataResult.getResult();

        if (Objects.nonNull(dataList) && !dataList.isEmpty()) {

            String permissionStr = dataList.stream().map(p -> {
                // 将每个权限添加ROLE_前缀
                return StrUtil.format("ROLE_{}", p);
            }).collect(Collectors.joining(","));

            iRedisService.remove(systemConfig.getTokenSign() + username);
            iRedisService.set(systemConfig.getTokenSign() + username, permissionStr);

            RedisKeysManager.addRedisKey(systemConfig.getTokenSign() + username);

        }

    }

    /**
     * 判断账号是否被禁用
     *
     * @param username
     */
    protected void accountIsOff(String username) throws AccountOffException {

        UsersModel usersModel = userService.getUserByUsername(username);

        if (Objects.isNull(usersModel)) {
            throw new UserNameNullException("用户不存在");
        }

        if (!usersModel.getStatus()) {
            throw new AccountOffException("账户被禁用");
        }

    }

}
